from pathlib import Path
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired, Length
from flask import Flask, render_template, request, redirect, url_for, send_file, flash, current_app
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, UserMixin, login_user, login_required, logout_user, current_user
from werkzeug.security import generate_password_hash, check_password_hash
from mutagen.mp3 import MP3
import os

app = Flask(__name__)
app.config['SECRET_KEY'] = 'csksdjKey'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///database.db'
app.config['UPLOAD_FOLDER'] = 'static/songs'
app.config['LYRICS_FOLDER'] = 'static/lyrics'

db = SQLAlchemy(app)
login_manager = LoginManager(app)
login_manager.login_view = 'login'

# 数据库模型
class User(UserMixin, db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(100), unique=True)
    password_hash = db.Column(db.String(200))
    two_factor_auth = db.Column(db.Boolean, default=False)
    profile_visible = db.Column(db.Boolean, default=True)
    default_playlist_public = db.Column(db.Boolean, default=False)
    tracking_protection = db.Column(db.Boolean, default=True)
    auto_clear_cookies = db.Column(db.Boolean, default=False)

    def set_password(self, password):
        self.password_hash = generate_password_hash(password)

    def check_password(self, password):
        return check_password_hash(self.password_hash, password)


class Playlist(db.Model):
    __table_args__ = (
        db.UniqueConstraint('user_id', 'name', name='unique_user_playlist'),
    )
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(50), nullable=False)  # 限制长度
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    is_public = db.Column(db.Boolean, default=False, nullable=False)
    created_at = db.Column(db.DateTime, server_default=db.func.now())
    songs = db.relationship('Song',
                            secondary='playlist_song',
                            backref=db.backref('playlists', lazy='dynamic'),
                            lazy='dynamic')

class Song(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(100))
    filename = db.Column(db.String(200))
    lyrics_file = db.Column(db.String(200))

playlist_song = db.Table('playlist_song',
    db.Column('playlist_id', db.Integer, db.ForeignKey('playlist.id')),
    db.Column('song_id', db.Integer, db.ForeignKey('song.id'))
)

class PlaylistForm(FlaskForm):
    name = StringField('歌单名称', validators=[
        DataRequired(message="名称不能为空"),
        Length(max=50, message="名称不能超过50个字符")
    ])
    submit = SubmitField('创建歌单')


@login_manager.user_loader
def load_user(user_id):
    return User.query.get(int(user_id))

# 路由设置
@app.route('/')
def index():
    if current_user.is_authenticated:
        # 仅获取公开歌单（排除用户私有歌单）
        public_playlists = Playlist.query.filter(
            Playlist.is_public == True,
            Playlist.user_id != current_user.id
        ).limit(12).all()

        return render_template('index.html',
                               public_playlists=public_playlists)
    return render_template('index.html')


@app.route('/privacy_settings', methods=['GET', 'POST'])
@login_required
def privacy_settings():
    if request.method == 'POST':
        try:
            # 处理账户安全设置
            current_user.two_factor_auth = 'two_factor_auth' in request.form
            current_user.profile_visible = request.form.get('account_visibility') == 'public'

            # 处理默认歌单可见性
            current_user.default_playlist_public = request.form.get('default_visibility') == 'public'

            # 处理现有歌单可见性
            for playlist in current_user.playlists:
                key = f"playlist_{playlist.id}_visibility"
                playlist.is_public = key in request.form  # 直接检查是否存在该字段

            # 处理浏览器设置
            current_user.tracking_protection = 'tracking_protection' in request.form
            current_user.auto_clear_cookies = 'auto_clear_cookies' in request.form

            db.session.commit()
            flash('隐私设置已保存', 'success')
        except Exception as e:
            db.session.rollback()
            current_app.logger.error(f'保存失败: {str(e)}')
            flash(f'保存失败: {str(e)}', 'danger')

    return render_template('privacy_settings.html')

@app.route('/register', methods=['GET', 'POST'])
def register():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        user = User(username=username)
        user.set_password(password)
        db.session.add(user)
        db.session.commit()
        return redirect(url_for('login'))
    return render_template('register.html')

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        user = User.query.filter_by(username=username).first()
        if user and user.check_password(password):
            login_user(user)
            return redirect(url_for('index'))
    return render_template('login.html')

@app.route('/logout')
@login_required
def logout():
    logout_user()
    return redirect(url_for('index'))


@app.route('/create_playlist', methods=['GET', 'POST'])
@login_required
def create_playlist():
    form = PlaylistForm()

    if form.validate_on_submit():
        try:
            # 检查重复歌单
            existing = Playlist.query.filter_by(
                name=form.name.data,
                user_id=current_user.id
            ).first()

            if existing:
                flash('您已经拥有同名歌单', 'warning')
                return redirect(url_for('create_playlist'))

            # 创建新歌单
            new_playlist = Playlist(
                name=form.name.data.strip(),
                user_id=current_user.id
            )
            db.session.add(new_playlist)
            db.session.commit()
            flash('歌单创建成功!', 'success')
            return redirect(url_for('view_playlist', playlist_id=new_playlist.id))

        except Exception as e:
            db.session.rollback()
            flash('创建失败，请稍后再试', 'danger')
            app.logger.error(f"创建歌单错误: {str(e)}")

    # 显示验证错误
    elif request.method == 'POST':
        flash('请检查表单中的错误', 'danger')

    return render_template('create_playlist.html', form=form)

@app.route('/playlist/<int:playlist_id>')
@login_required
def view_playlist(playlist_id):
    playlist = Playlist.query.get_or_404(playlist_id)
    return render_template('playlist.html', playlist=playlist)

@app.route('/songs')
@login_required
def song_list():
    songs = []
    for file in Path(app.config['UPLOAD_FOLDER']).glob('*.*'):
        if file.suffix.lower() in ['.mp3', '.wav', '.flac']:
            filename = file.stem
            parts = filename.split('-')
            title = parts[0].strip()
            artist = parts[1].strip() if len(parts) > 1 else "未知艺术家"
            audio = MP3(file)
            duration = int(audio.info.length)
            mins, secs = divmod(duration, 60)
            songs.append({
                'title': title,
                'artist': artist,
                'file': file.name,
                'duration': f"{mins:02d}:{secs:02d}"
            })
    return render_template('songs.html', songs=songs)

@app.route('/song/<int:song_id>')
@login_required
def song_detail(song_id):
    song = Song.query.get_or_404(song_id)
    lyrics_path = os.path.join(app.config['LYRICS_FOLDER'], song.lyrics_file)
    with open(lyrics_path, 'r') as f:
        lyrics = f.read()
    return render_template('song_detail.html', song=song, lyrics=lyrics)

if __name__ == '__main__':
    with app.app_context():
        db.create_all()
    app.run(debug=True)
